package com.example.redis.service;

import cn.hutool.core.util.StrUtil;
import cn.hutool.extra.spring.SpringUtil;
import com.example.redis.config.RedisConfig;
import org.springframework.data.redis.core.RedisTemplate;

import java.time.Duration;
import java.util.Collection;
import java.util.Map;

/**
 * @version 1.0.0
 * @description:
 * @author: guorf
 * @time: 2021/12/6 11:23
 */
public class RedisService {
    private RedisTemplate<String, Object> redisTemplate;

    // key前缀
    private String keyPrefix;
    // 过期时间
    private Duration expired;

    public RedisService(Map<String, Object> param) {
        this.redisTemplate = SpringUtil.getBean(RedisConfig.class).getRedisTemplateByDb(param);
        this.keyPrefix = param.get("prefix").toString();
        this.expired = (Duration)param.get("expired");
    }
    /**
     * @description: 构造key(无后缀)
     * @return: java.lang.String
     * @author: guorf
     * @time: 2021/12/6 11:56
     */
    private String constructionKey() {
        return constructionKey(null);
    }
    /**
     * @description: 构造key
     * @param key
     * @return: java.lang.String
     * @author: guorf
     * @time: 2021/12/6 11:56
     */
    private String constructionKey(String key) {
        return keyPrefix + (StrUtil.isBlank(key) ? "" : ":"+key);
    }

    /**
     * 将参数中的字符串值设置为键的值，不设置过期时间
     * @param value 必须要实现 Serializable 接口
     */
    public void set(Object value) {
        redisTemplate.opsForValue().set(constructionKey(), value, expired);
    }
    /**
     * 将参数中的字符串值设置为键的值，不设置过期时间
     * @param key
     * @param value 必须要实现 Serializable 接口
     */
    public void set(String key, Object value) {
        redisTemplate.opsForValue().set(constructionKey(key), value, expired);
    }

    /**
     * 将参数中的字符串值设置为键的值，设置过期时间
     * @param value 必须要实现 Serializable 接口
     * @param timeout
     */
    public void set(Object value, Duration timeout) {
        redisTemplate.opsForValue().set(constructionKey(), value, timeout);
    }

    /**
     * 将参数中的字符串值设置为键的值，设置过期时间
     * @param key
     * @param value 必须要实现 Serializable 接口
     * @param timeout
     */
    public void set(String key, Object value, Duration timeout) {
        redisTemplate.opsForValue().set(constructionKey(key), value, timeout);
    }

    /**
     * 获取与指定键相关的值
     * @return
     */
    public Object get() {
        return redisTemplate.opsForValue().get(constructionKey());
    }

    /**
     * 获取与指定键相关的值
     * @param key
     * @return
     */
    public Object get(String key) {
        return redisTemplate.opsForValue().get(constructionKey(key));
    }

    /**
     * 设置某个键的过期时间(空key则直接使用前缀)
     * @param ttl 过期秒数
     */
    public boolean expire(Duration ttl) {
        return redisTemplate.expire(constructionKey(), ttl);
    }

    /**
     * 设置某个键的过期时间
     * @param key 键值
     * @param ttl 过期秒数
     */
    public boolean expire(String key, Duration ttl) {
        return redisTemplate.expire(constructionKey(key), ttl);
    }

    /**
     * 判断某个键是否存在
     * @param key 键值
     */
    public boolean hasKey(String key) {
        return redisTemplate.hasKey(key);
    }


    /**
     * 获取Hash结构中的属性
     */
    public Object hGet(String key, String hashKey){
        return redisTemplate.opsForHash().get(key, hashKey);
    }

    /**
     * 向Hash结构中放入一个属性
     */
    public Boolean hSet(String key, String hashKey, Object value, Duration ttl){
        redisTemplate.opsForHash().put(key, hashKey, value);
        return expire(key, ttl);
    }

    /**
     * 向Hash结构中放入一个属性
     */
    public void hSet(String key, String hashKey, Object value){
        redisTemplate.opsForHash().put(key, hashKey, value);
    }

    /**
     * 直接获取整个Hash结构
     */
    public Map<Object, Object> hGetAll(String key){
        return redisTemplate.opsForHash().entries(key);
    }

    /**
     * 直接设置整个Hash结构
     */
    public Boolean hSetAll(String key, Map<String, Object> map, Duration ttl){
        redisTemplate.opsForHash().putAll(key, map);
        return expire(key, ttl);
    }

    /**
     * 直接设置整个Hash结构
     */
    public void hSetAll(String key, Map<String, ?> map){
        redisTemplate.opsForHash().putAll(key, map);
    }

    /**
     * 删除Hash结构中的属性
     */
    public void hDel(String key, Object... hashKey){
        redisTemplate.opsForHash().delete(key, hashKey);
    }

    /**
     * 判断Hash结构中是否有该属性
     */
    public Boolean hHasKey(String key, String hashKey){
        return redisTemplate.opsForHash().hasKey(key, hashKey);
    }

    /**
     * Hash结构中属性递增
     */
    public Long hIncr(String key, String hashKey, Long delta){
        return redisTemplate.opsForHash().increment(key, hashKey, delta);
    }

    /**
     * Hash结构中属性递减
     */
    public Long hDecr(String key, String hashKey, Long delta){
        return redisTemplate.opsForHash().increment(key, hashKey, -delta);
    }

    /**
     * 向集合添加元素
     * @param key
     * @param value
     * @return 返回值为设置成功的value数
     */
//    public static Long sAdd(String key, String... value) {
//        return redisUtil.redisTemplate.opsForSet().add(key, value);
//    }

    /**
     * 获取集合中的某个元素
     * @param key
     * @return 返回值为redis中键值为key的value的Set集合
     */
//    public static Set<String> sGetMembers(String key) {
//        return redisUtil.redisTemplate.opsForSet().members(key);
//    }

    /**
     * 获取集合中的某个元素
     * @param keyPrefix
     * @return 返回值为redis中键值为key的value的Set集合
     */
//    public static Set<String> getKeys(String keyPrefix ) {
//        return redisUtil.redisTemplate.keys(keyPrefix+"*");
//    }

    /**
     * 将给定分数的指定成员添加到键中存储的排序集合中
     * @param key
     * @param value
     * @param score
     * @return
     */
//    public static Boolean zAdd(String key, String value, double score) {
//        return redisUtil.redisTemplate.opsForZSet().add(key, value, score);
//    }

    /**
     * 返回指定排序集中给定成员的分数
     * @param key
     * @param value
     * @return
     */
//    public static Double zScore(String key, String value) {
//        return redisUtil.redisTemplate.opsForZSet().score(key, value);
//    }

    /**
     * 删除指定的键
     * @param key
     * @return
     */
    public Boolean delete(String key) {
        return redisTemplate.delete(key);
    }

    /**
     * 删除多个键
     * @param keys
     * @return
     */
    public Long delete(Collection<String> keys) {
        return redisTemplate.delete(keys);
    }
}
